package handler

import (
	"account-service/models"
	"account-service/tools"
	"context"
	"math"
	"strconv"
	"strings"
	"time"

	pbAuth "account-service/proto/auth"
	pbParams "account-service/proto/params"
	pbResult "account-service/proto/result"
	pbRole "account-service/proto/role"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

/*
 +----------------------------------------------------------------------
 + Title        : RoleHandler
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2019-08-08
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : 角色处理
 +----------------------------------------------------------------------
*/

type RoleHandler struct {
	pbRole.UnimplementedRoleSrvServer
}

/**
 * 新增角色
 *
 * @param string Name ---------------------------------必传,名称
 * @param int IsAdmin ---------------------------------非必传,是否管理员
 * @param int Status ----------------------------------非必传,状态
 * @param string Note ---------------------------------非必传,备注
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *RoleHandler) AddRole(ctx context.Context, req *pbRole.AddRoleRequest) (*pbResult.Result, error) {
	if req.Name == "" {
		return nil, status.Errorf(codes.InvalidArgument, "请输入名称")
	}

	//判断名称是否存在【唯一性】
	var total int64
	err := models.Role{}.GetTotalByParams(&models.Role{}, &total, map[string]interface{}{
		"name":        req.Name,
		"status <> ?": -2,
	})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if total > 0 {
		return nil, status.Errorf(codes.Aborted, "角色名称已经存在")
	}

	i, err := models.Role{}.Add(&models.Role{
		Name:    req.Name,
		IsAdmin: int8(req.IsAdmin),
		Note:    req.Note,
		Status:  int8(req.Status),
	})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if i <= 0 {
		return nil, status.Errorf(codes.Aborted, "新增角色失败")
	}

	return &pbResult.Result{Code: 200, Msg: "新增角色成功"}, nil
}

/**
 * 删除角色
 *
 * @param string Ids ----------------------------------必传,角色ID,支持多个
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *RoleHandler) DeleteRole(ctx context.Context, req *pbParams.IdsRequest) (*pbResult.Result, error) {
	ids := strings.TrimRight(req.Ids, ",")
	if ids == "" {
		return nil, status.Errorf(codes.InvalidArgument, "角色ID错误")
	}

	roleIds := tools.IntSplit(ids, ",")
	//判断角色是否已绑定账户
	var total int64
	err := models.AccountRole{}.GetTotalByParams(&models.AccountRole{}, &total, map[string]interface{}{"role_id IN (?)": roleIds})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	if total > 0 {
		return nil, status.Errorf(codes.Aborted, "角色已绑定账户,不允许删除")
	}

	result, err := models.Role{}.EditByParams(&models.Role{}, map[string]interface{}{"status": -2, "update_time": time.Now()}, map[string]interface{}{"id IN (?)": roleIds})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if result <= 0 {
		return nil, status.Errorf(codes.Aborted, "删除角色失败")
	}

	return &pbResult.Result{Code: 200, Msg: "删除角色成功"}, nil
}

/**
 * 编辑角色
 *
 * @param int Id --------------------------------------必传,角色Id
 * @param string Name ---------------------------------非必传,名称
 * @param string IsAdmin ------------------------------非必传,是否管理员
 * @param string Note ---------------------------------非必传,备注
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *RoleHandler) EditRole(ctx context.Context, req *pbRole.EditRoleRequest) (*pbResult.Result, error) {
	if req.Id <= 0 {
		return nil, status.Errorf(codes.InvalidArgument, "角色Id错误")
	}

	params := map[string]interface{}{
		"update_time": time.Now(),
	}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsAdmin != "all" {
		params["is_admin"] = req.IsAdmin
	}
	if req.Note != "" {
		params["note"] = req.Note
	}

	//判断角色名称是否存在【唯一性】
	if req.Name != "" {
		var total int64
		err := models.Role{}.GetTotalByParams(&models.Role{}, &total, map[string]interface{}{
			"name":        req.Name,
			"status <> ?": -2,
			"id <> ?":     req.Id,
		})
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}
		if total > 0 {
			return nil, status.Errorf(codes.Aborted, "角色名称已经存在")
		}
	}

	//编辑
	i, err := models.Role{}.EditByPrimaryKey(&models.Role{}, params, req.Id)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if i <= 0 {
		return nil, status.Errorf(codes.Aborted, "编辑角色失败")
	}

	return &pbResult.Result{Code: 200, Msg: "编辑角色成功"}, nil
}

/**
 * 编辑角色状态
 *
 * @param string Ids ----------------------------------必传,角色Id支持多个
 * @param int32 Status --------------------------------必传,状态
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *RoleHandler) EditRoleStatus(ctx context.Context, req *pbParams.EditStatusRequest) (*pbResult.Result, error) {
	if req.Ids == "" {
		return nil, status.Errorf(codes.InvalidArgument, "角色Id错误")
	}
	if !tools.IsContainNumber([]int{-1, 1}, int(req.Status)) {
		return nil, status.Errorf(codes.InvalidArgument, "角色状态错误")
	}

	//如果禁用角色需要判断是否绑定账户
	if req.Status == -1 {
		//判断角色是否绑定账户
		var total int64
		err := models.AccountRole{}.GetTotalByParams(&models.AccountRole{}, &total, map[string]interface{}{
			"role_id IN (?)": req.Ids,
		})
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}
		if total > 0 {
			return nil, status.Errorf(codes.Aborted, "角色已绑定账户,不允许删除")
		}
	}

	roleIds := tools.IntSplit(strings.TrimRight(req.Ids, ","), ",")
	result, err := models.Role{}.EditByParams(&models.Role{}, map[string]interface{}{
		"status":      req.Status,
		"update_time": time.Now(),
	}, map[string]interface{}{"id IN (?)": roleIds})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	message := ""
	if req.Status == 1 {
		message = "启用角色"
	} else {
		message = "禁用角色"
	}
	if result <= 0 {
		return nil, status.Errorf(codes.Aborted, message+"失败")
	}

	return &pbResult.Result{Code: 200, Msg: message + "成功"}, nil
}

/**
 * 角色详情
 *
 * @param int Id --------------------------------------必传,角色Id
 * @param int IsHaveAuth ------------------------------非必传,是否获取权限数据
 * @return *pbRole.RoleDetailResponse, errors
 * @author huwl
 */
func (e *RoleHandler) RoleDetail(ctx context.Context, req *pbRole.RoleDetailRequest) (*pbRole.RoleDetailResponse, error) {
	id := req.Id
	if id <= 0 {
		return nil, status.Errorf(codes.InvalidArgument, "角色Id错误")
	}

	//获取角色信息
	role := models.Role{}
	result, err := models.Role{}.GetResultByPrimaryKey(&role, id)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if result <= 0 || role.Status == -2 {
		return nil, status.Errorf(codes.Aborted, "角色信息错误")
	}

	//获取权限
	authes := []*pbAuth.Auth{}
	if req.IsHaveAuth == 1 {
		roleAuthes := []models.RoleAuth{}
		err := models.RoleAuth{}.GetResultsByParams(&models.RoleAuth{}, &roleAuthes, map[string]interface{}{"role_id": id}, 1, -1, "id asc")
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}

		authIds := []interface{}{}
		for _, roleAuthe := range roleAuthes {
			authIds = append(authIds, roleAuthe.AuthId)
		}

		authItems := []models.Auth{}
		err = models.Auth{}.Rows(&authItems, authIds)
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}

		for _, authItem := range authItems {
			authes = append(authes, &pbAuth.Auth{
				Id:             uint32(authItem.Id),
				Pid:            uint32(authItem.Pid),
				Name:           authItem.Name,
				ControllerName: authItem.ControllerName,
				ActionName:     authItem.ActionName,
				IsMenu:         uint32(authItem.IsMenu),
				Status:         int32(authItem.Status),
				Note:           authItem.Note,
				CreateTime:     authItem.CreateTime.Format("2006-01-02 15:04:05"),
				UpdateTime:     authItem.UpdateTime.Format("2006-01-02 15:04:05"),
			})
		}
	}

	return &pbRole.RoleDetailResponse{
		Role: &pbRole.Role{
			Id:         uint32(role.Id),
			Name:       role.Name,
			IsAdmin:    int32(role.IsAdmin),
			Note:       role.Note,
			Status:     int32(role.Status),
			CreateTime: role.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime: role.UpdateTime.Format("2006-01-02 15:04:05"),
		},
		Authes: authes,
	}, nil
}

/**
 * 获取单条角色数据
 *
 * @param string Name ---------------------------------非必传,名称
 * @param string IsAdmin ------------------------------非必传,是否管理員
 * @param string Status -------------------------------非必传,状态
 * @return *pbRole.RoleDetailResponse, error
 * @author huwl
 */
func (e *RoleHandler) Row(ctx context.Context, req *pbRole.QueryRoleRequest) (*pbRole.RoleDetailResponse, error) {
	params := map[string]interface{}{}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsAdmin != "all" {
		i, _ := strconv.Atoi(req.IsAdmin)
		params["is_cash"] = i
	}
	if req.Status != "all" {
		params["status"] = req.Status
	}

	role := models.Role{}
	i, err := models.Role{}.Row(&models.Role{}, &role, params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if i <= 0 || role.Status == -2 {
		return nil, status.Errorf(codes.Aborted, "角色信息错误")
	}

	return &pbRole.RoleDetailResponse{
		Role: &pbRole.Role{
			Id:         uint32(role.Id),
			Name:       role.Name,
			IsAdmin:    int32(role.IsAdmin),
			Note:       role.Note,
			Status:     int32(role.Status),
			CreateTime: role.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime: role.UpdateTime.Format("2006-01-02 15:04:05"),
		},
	}, nil
}

/**
 * 根据多个角色ID获取角色数据
 *
 * @param string ids ----------------------------------必传,名称
 * @return *pbRole.RoleListResponse, error
 * @author huwl
 */
func (e *RoleHandler) Rows(ctx context.Context, req *pbParams.IdsRequest) (*pbRole.RoleListResponse, error) {
	ids := req.Ids
	roleIds := []interface{}{}
	itemIds := tools.IntSplit(ids, ",")
	for _, itemId := range itemIds {
		roleIds = append(roleIds, itemId)
	}

	roles := []models.Role{}
	err := models.Role{}.Rows(&roles, roleIds)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	roleItems := []*pbRole.Role{}
	for _, role := range roles {
		roleItems = append(roleItems, &pbRole.Role{
			Id:         uint32(role.Id),
			Name:       role.Name,
			IsAdmin:    int32(role.IsAdmin),
			Note:       role.Note,
			Status:     int32(role.Status),
			CreateTime: role.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime: role.UpdateTime.Format("2006-01-02 15:04:05"),
		})
	}

	return &pbRole.RoleListResponse{
		Roles: roleItems,
	}, nil
}

/**
 * 角色列表
 *
 * @param int Id --------------------------------------非必传,角色ID
 * @param string Ids ----------------------------------非必传,角色ID,支持多个
 * @param string Name ---------------------------------非必传,名稱
 * @param string IsAdmin ------------------------------非必传,是否管理
 * @param string Status -------------------------------非必传,状态支持多个：1,-1
 * @param string StartCreateTime ----------------------非必传,开始创建时间
 * @param string EndCreateTime ------------------------非必传,结束创建时间
 * @param string SortType -----------------------------非必传,排序方式
 * @param string SortField ----------------------------非必传,排序字段
 * @param uint32 PageSize -----------------------------非必传,条数
 * @param uint32 Page ---------------------------------非必传,页码
 * @return *pbRole.RoleListResponse, error
 * @author huwl
 */
func (e *RoleHandler) RoleList(ctx context.Context, req *pbRole.QueryRoleRequest) (*pbRole.RoleListResponse, error) {
	params := map[string]interface{}{
		"status <> ?": -2,
	}
	if req.Id > 0 {
		params["id"] = req.Id
	}
	if req.Ids != "" {
		params["id in (?)"] = tools.IntSplit(req.Ids, ",")
	}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsAdmin != "all" {
		i, _ := strconv.Atoi(req.IsAdmin)
		params["is_admin"] = i
	}
	if req.Status != "all" {
		params["status in (?)"] = tools.IntSplit(req.Status, ",")
	}
	if req.StartCreateTime != "" {
		params["create_time >= ?"] = req.StartCreateTime + " 00:00:00"
	}
	if req.EndCreateTime != "" {
		params["create_time <= ?"] = req.EndCreateTime + " 23:59:59"
	}
	if req.SortField == "" {
		req.SortField = "id"
	}
	if req.SortType == "" {
		req.SortType = "desc"
	}
	if req.PageSize == 0 {
		req.PageSize = 20
	}
	if req.Page == 0 {
		req.Page = 1
	}

	//获取角色数量
	var total int64
	err := models.Role{}.GetTotalByParams(&models.Role{}, &total, params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	//获取角色数据
	roles := []models.Role{}
	roleItemValues := []models.Role{}
	if total > 0 {
		err = models.Role{}.GetResultsByParams(&models.Role{}, &roles, params, int(req.Page), int(req.PageSize), req.SortField+" "+req.SortType)
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}

		//获取权限
		if req.IsHaveAuth == 1 {
			roleIds := []int{}
			for _, roleItem := range roles {
				if roleItem.IsAdmin != 1 {
					roleIds = append(roleIds, int(roleItem.Id))
				}
			}

			//获取角色权限
			roleAuthes := []models.RoleAuth{}
			err = models.RoleAuth{}.GetResultsByParams(&models.RoleAuth{}, &roleAuthes, map[string]interface{}{
				"role_id in (?)": roleIds,
			}, 1, -1, "id desc")
			if err != nil {
				return nil, status.Errorf(codes.Aborted, err.Error())
			}

			tempIds := []uint16{}
			authIds := []interface{}{}
			for _, item := range roleAuthes {
				if !tools.IsContainNumber(tempIds, item.AuthId) {
					tempIds = append(tempIds, item.AuthId)
					authIds = append(authIds, item.AuthId)
				}
			}

			roleValues := []models.Role{}
			for _, roleValue := range roles {
				for _, roleAuth := range roleAuthes {
					if roleValue.Id == roleAuth.RoleId {
						roleValue.AuthIds = append(roleValue.AuthIds, roleAuth.AuthId)
					}
				}

				roleValues = append(roleValues, roleValue)
			}

			authes := []models.Auth{}
			err = models.Auth{}.Rows(&authes, authIds)
			if err != nil {
				return nil, status.Errorf(codes.Aborted, err.Error())
			}

			for _, item := range roleValues {
				for _, auth := range authes {
					for _, vv := range item.AuthIds {
						if vv == auth.Id {
							item.Authes = append(item.Authes, auth)
						}
					}
				}

				roleItemValues = append(roleItemValues, item)
			}
		}
	}

	//组装角色数据
	roleItems := []*pbRole.Role{}
	if req.IsHaveAuth == 1 {
		for _, role := range roleItemValues {
			authItems := []*pbAuth.Auth{}
			for _, auth := range role.Authes {
				authItems = append(authItems, &pbAuth.Auth{
					Id:             uint32(auth.Id),
					Pid:            uint32(auth.Pid),
					Name:           auth.Name,
					ControllerName: auth.ControllerName,
					ActionName:     auth.ActionName,
					IsMenu:         uint32(auth.IsMenu),
					Status:         int32(auth.Status),
					Note:           auth.Note,
					CreateTime:     auth.CreateTime.Format("2006-01-02 15:04:05"),
					UpdateTime:     auth.UpdateTime.Format("2006-01-02 15:04:05"),
				})
			}
			roleItems = append(roleItems, &pbRole.Role{
				Id:         uint32(role.Id),
				Name:       role.Name,
				IsAdmin:    int32(role.IsAdmin),
				Note:       role.Note,
				Status:     int32(role.Status),
				CreateTime: role.CreateTime.Format("2006-01-02 15:04:05"),
				UpdateTime: role.UpdateTime.Format("2006-01-02 15:04:05"),
				Authes:     authItems,
			})
		}
	} else {
		for _, role := range roles {
			roleItems = append(roleItems, &pbRole.Role{
				Id:         uint32(role.Id),
				Name:       role.Name,
				IsAdmin:    int32(role.IsAdmin),
				Note:       role.Note,
				Status:     int32(role.Status),
				CreateTime: role.CreateTime.Format("2006-01-02 15:04:05"),
				UpdateTime: role.UpdateTime.Format("2006-01-02 15:04:05"),
				Authes:     []*pbAuth.Auth{},
			})
		}
	}

	pageTotal := math.Ceil(float64(total) / float64(req.PageSize))
	return &pbRole.RoleListResponse{
		Roles: roleItems,
		ListResult: &pbResult.ListCommonResult{
			Page:      req.Page,
			Total:     uint32(total),
			PageSize:  req.PageSize,
			PageTotal: uint32(pageTotal),
		},
	}, nil
}

/**
 * 角色數量
 *
 * @param uint32 Id -----------------------------------非必传,角色ID
 * @param string Ids ----------------------------------非必传,角色ID,支持多个
 * @param string Name ---------------------------------非必传,名稱
 * @param string IsAdmin ------------------------------非必传,是否管理
 * @param string Status -------------------------------非必传,状态支持多个：1,-1
 * @param string StartCreateTime ----------------------非必传,开始创建时间
 * @param string EndCreateTime ------------------------非必传,结束创建时间
 * @return *pbResult.TotalResult, error
 * @author huwl
 */
func (e *RoleHandler) RoleTotal(ctx context.Context, req *pbRole.QueryRoleRequest) (*pbResult.TotalResult, error) {
	params := map[string]interface{}{
		"status <> ?": -2,
	}
	if req.Id > 0 {
		params["id"] = req.Id
	}
	if req.Ids != "" {
		params["id in (?)"] = tools.IntSplit(req.Ids, ",")
	}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsAdmin != "all" {
		i, _ := strconv.Atoi(req.IsAdmin)
		params["is_admin"] = i
	}
	if req.Status != "all" {
		params["status in (?)"] = tools.IntSplit(req.Status, ",")
	}
	if req.StartCreateTime != "" {
		params["create_time >= ?"] = req.StartCreateTime + " 00:00:00"
	}
	if req.EndCreateTime != "" {
		params["create_time <= ?"] = req.EndCreateTime + " 23:59:59"
	}

	//获取角色数量
	var total int64
	err := models.Role{}.GetTotalByParams(&models.Role{}, &total, params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	return &pbResult.TotalResult{
		Total: uint32(total),
	}, nil
}

/**
 * 绑定权限【绑定 + 取消绑定功能聚合一起】
 *
 * @param int RoleId ----------------------------------必传,角色ID
 * @param string AuthIds ------------------------------非必传,权限ID
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *RoleHandler) BindAuth(ctx context.Context, req *pbRole.BindAuthRequest) (*pbResult.Result, error) {
	authIds := strings.TrimRight(req.AuthIds, ",")

	if req.RoleId <= 0 {
		return nil, status.Errorf(codes.InvalidArgument, "角色ID错误")
	}

	//获取该角色的权限
	roleAuthes := []models.RoleAuth{}
	err := models.RoleAuth{}.GetResultsByParams(&models.RoleAuth{}, &roleAuthes, map[string]interface{}{"role_id": req.RoleId}, 1, -1, "id desc")
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	if len(roleAuthes) > 0 {
		//先删除
		result, err := models.RoleAuth{}.DeleteByParams(&models.RoleAuth{}, map[string]interface{}{"role_id": req.RoleId})
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}
		if result <= 0 {
			return nil, status.Errorf(codes.Aborted, "绑定权限失败")
		}
	}

	if authIds == "" {
		return &pbResult.Result{Code: 200, Msg: "绑定权限成功"}, nil
	}

	// 后新增
	ids := tools.IntSplit(authIds, ",")
	params := []models.RoleAuth{}
	for _, v := range ids {
		params = append(params, models.RoleAuth{
			AuthId: uint16(v),
			RoleId: uint16(req.RoleId),
		})
	}

	result, err := models.RoleAuth{}.Add(&params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if result <= 0 {
		return nil, status.Errorf(codes.Aborted, "绑定权限失败")
	}

	return &pbResult.Result{Code: 200, Msg: "绑定权限成功"}, nil
}
